import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import CommonConstants from '../constants/CommonConstants';
import deviceInfo from '@ohos.deviceInfo';
import Network from '@system.network';
import Logger from './Logger';
import CryptoJS from '@ohos/crypto-js';
import { DownResult } from '../bean/DownResult';
import { UpgradeResult } from '../bean/UpgradeResult';
import connection from '@ohos.net.connection';

const TAG: string = 'HttpUtil'
const HTTP_INFO: boolean = true

/**
 * 发送POST网路请求
 * @param url 请求地址
 * @param extData 请求参数
 * @returns 异步返回HttpResponse请求结果
 */
function httpRequest(url: string, extData: string | Object | ArrayBuffer) {
    Logger.debug(TAG, `uri=${url}, extData=${JSON.stringify(extData, null, 4)}`)
    // 每一个httpRequest对应一个HTTP请求任务，不可复用
    let httpRequest: http.HttpRequest = http.createHttp();
    let options: http.HttpRequestOptions = {
        // 可选，默认为http.RequestMethod.GET
        method: http.RequestMethod.POST,
        extraData: extData,
        // 读取超时，默认为60000ms
        readTimeout: 60000,
        // 连接超时，默认为60000ms
        connectTimeout: 60000,
        // 请求头
        header: {
            'Content-Type': 'application/json'
        },
    }
    return new Promise<http.HttpResponse>((resolve, reject) => {
        httpRequest.request(url, options)
            .then((response) => {
                if (HTTP_INFO) {
                    Logger.info(TAG, `res.header=${JSON.stringify(response.header)}`)
                    Logger.info(TAG, `res.result=${JSON.stringify(response.result)}`)
                    Logger.info(TAG, `res.resultType=${JSON.stringify(response.resultType)}`)
                    Logger.info(TAG, `res.responseCode=${JSON.stringify(response.responseCode)}`)
                    Logger.info(TAG, `res.cookies=${JSON.stringify(response.cookies)}`)
                }
                resolve(response)
            })
            .catch((err: BusinessError) => {
                Logger.error(TAG, `req err=${JSON.stringify(err)}`)
                reject(err)
            })
            .finally(() => {
                // 当该请求使用完毕时，开发者务必调用destroy方法主动销毁
                httpRequest.destroy();
            })
    })
}

/**
 * 处理设备注册的参数，进行设备注册的网路请求
 * @returns 异步返回设备注册的网路请求结果
 */
export function register() {
    let registerUrl = `${CommonConstants.SERVER}register/${CommonConstants.PRODUCT_ID}`
    const timestamp: number = Math.round(new Date().getTime() / 1000)
    let oldStr: string = CommonConstants.MID + CommonConstants.PRODUCT_ID + timestamp
    let key: string = CommonConstants.PRODUCT_SECRET
    let md5: string = CryptoJS.HmacMD5(oldStr, key).toString()
    Logger.debug(TAG, `calculate hmac md5 hash succeed:${md5}`);
    return new Promise<http.HttpResponse>((resolve, reject) => {
        Network.getType({
            success: (data) => {
                let netType = data.type
                let extData = {
                    mid: CommonConstants.MID,
                    oem: CommonConstants.OEM,
                    models: CommonConstants.MODELS,
                    platform: CommonConstants.PLATFORM,
                    deviceType: CommonConstants.DEVICES_TYPE,
                    timestamp: timestamp,
                    sign: md5,
                    sdkversion: deviceInfo.sdkApiVersion,
                    appversion: CommonConstants.APP_VERSION,
                    version: deviceInfo.displayVersion,
                    networkType: netType,
                }
                resolve(httpRequest(registerUrl, extData))
            },
            fail: (data, code) => {
                Logger.error(TAG, `getNetworkType fail, data=${data},code=${code}`)
                reject(`getNetworkType fail, data=${data},code=${code}`)
            }
        })
    })
}

/**
 * 处理检查新版本的参数，进行检查新版本的网路请求
 * @returns 异步返回检查新版本网路请求结果
 */
export function checkVersion(devicesId: string, deviceSecret: string, curVersion: string) {
    let checkVersionUrl = `${CommonConstants.SERVER}product/${CommonConstants.PRODUCT_ID}/${devicesId}/ota/checkVersion`
    const timestamp: number = Math.round(new Date().getTime() / 1000)
    let oldStr: string = devicesId + CommonConstants.PRODUCT_ID + timestamp
    let key = deviceSecret
    let sign: string = CryptoJS.HmacMD5(oldStr, key).toString()
    Logger.debug(TAG, `calculate hmac md5 hash succeed:${sign}`);
    let extData = {
        mid: CommonConstants.MID,
        version: curVersion,
        timestamp: timestamp,
        sign: sign
    }
    return httpRequest(checkVersionUrl, extData)
}

/**
 * 处理下载上报的参数，进行下载上报的网路请求
 * @returns 异步返回下载上报网路请求结果
 */
export function reportDownResult(devicesId: string, deviceSecret: string, downResult: DownResult) {
    let reportDownResultUrl = `${CommonConstants.SERVER}product/${CommonConstants.PRODUCT_ID}/${devicesId}/ota/reportDownResult`
    const timestamp: number = Math.round(new Date().getTime() / 1000)
    let oldStr: string = devicesId + CommonConstants.PRODUCT_ID + timestamp
    let key = deviceSecret
    let sign: string = CryptoJS.HmacMD5(oldStr, key).toString()
    Logger.debug(TAG, `calculate hmac md5 hash succeed:${sign}`);
    let extData = {
        mid: CommonConstants.MID,
        timestamp: timestamp,
        sign: sign,
        deltaID: downResult.deltaID,
        downEnd: downResult.downEnd,
        downStart: downResult.downStart,
        downloadStatus: downResult.downloadStatus
    }
    return httpRequest(reportDownResultUrl, extData)
}

/**
 * 处理升级上报的参数，进行升级上报的网路请求
 * @returns 异步返回升级上报网路请求结果
 */
export function reportUpgradeResult(devicesId: string, deviceSecret: string, upgradeResult: UpgradeResult) {
    let reportUpgradeResultUrl = `${CommonConstants.SERVER}product/${CommonConstants.PRODUCT_ID}/${devicesId}/ota/reportUpgradeResult`
    const timestamp: number = Math.round(new Date().getTime() / 1000)
    let oldStr: string = devicesId + CommonConstants.PRODUCT_ID + timestamp
    let key = deviceSecret
    let sign: string = CryptoJS.HmacMD5(oldStr, key).toString()
    Logger.debug(TAG, `calculate hmac md5 hash succeed:${sign}`);
    let extData = {
        mid: CommonConstants.MID,
        timestamp: timestamp,
        sign: sign,
        deltaID: upgradeResult.deltaID,
        updateStatus: upgradeResult.updateStatus
    }
    return httpRequest(reportUpgradeResultUrl, extData)
}

/**
 * 注册网络监听
 * @returns 默认网络的连接对象
 */
export function listenNet(): connection.NetConnection {
    let currentNet = connection.createNetConnection()
    currentNet.register((error) => {
        if (error) {
            Logger.error(TAG, `Net.register err=${JSON.stringify(error)}`)
        } else {
            Logger.info(TAG, `Net register successfully`)
        }
    })
    currentNet.on("netUnavailable", (data) => {
        Logger.info(TAG, `网络是否可用：${hasNet()}`)
        AppStorage.setOrCreate('netAvailable', hasNet())
    })
    currentNet.on("netCapabilitiesChange", (data) => {
        Logger.info(TAG, `网络是否可用：${hasNet()}`)
        AppStorage.setOrCreate('netAvailable', hasNet())
    })
    currentNet.on("netConnectionPropertiesChange", (data) => {
        Logger.info(TAG, `网络是否可用：${hasNet()}`)
        AppStorage.setOrCreate('netAvailable', hasNet())
    })
    currentNet.on("netLost", (data) => {
        Logger.info(TAG, `网络是否可用：${hasNet()}`)
        AppStorage.setOrCreate('netAvailable', hasNet())
    })
    return currentNet
}

/**
 * 判断当前网络是否可用
 * @returns 网络可用-true；网络不可使用-false
 */
export function hasNet(): boolean {
    try {
        // 获取当前网络连接
        let netHandle = connection.getDefaultNetSync();
        // 0-100 为系统预留的连接
        if (!netHandle || netHandle.netId < 100) {
            return false;
        }
        // 获取连接的属性
        let netCapability = connection.getNetCapabilitiesSync(netHandle);
        let cap = netCapability.networkCap;
        if (!cap) {
            return false;
        }
        for (let em of cap) {
            if (connection.NetCap.NET_CAPABILITY_VALIDATED === em) {
                return true;
            }
        }
    } catch (e) {
        let err = e as BusinessError;
        Logger.error(TAG, 'get netInfo error ：' + JSON.stringify(err));
    }
    return false;
}

/**
 * 取消网络监听
 * @param currentNet 之前注册的需要取消监听的网络连接对象
 */
export function unListenNet(currentNet: connection.NetConnection) {
    currentNet.unregister((error) => {
        if (error) {
            Logger.error(TAG, `Net.unregister err=${JSON.stringify(error)}`)
        } else {
            Logger.info(TAG, `Net unregister successfully`)
        }
    })
}
